//
//  Vector.hpp
//  C3W_Demo_By_Fan
//
//  Created by 范静涛 on 2024/7/22.
//

//------------------------------------------------------------------------------
//【文件名】Vector.hpp
//【功能模块和目的】向量类模版定义及实现，用于存储T类型元素的N维度向量
//【开发者及日期】范静涛 2024/7/22
//【更改记录】2024/8/9 范静涛 修改维度大小(维数)常数据成员标识符为全大写DIMENSION
//------------------------------------------------------------------------------

#ifndef Vector_hpp
#define Vector_hpp

//size_t所属头文件
#include <cstddef>
//std异常基类所属头文件
#include <stdexcept>
//std::string字符串类所属头文件
#include <string>
//std::array长度固定数组类模版所属头文件
#include <array>
//std::find函数所属头文件
#include <algorithm>
//std::istream和ostream所属头文件
#include <iostream>
//std::abs、sqrt函数所属头文件
#include <cmath>
//静态容器类模版头文件
#include "StaticContainer.hpp"

//------------------------------------------------------------------------------
//【类模版名】Vector
//【功能】N维度向量模版
//【接口说明】
//    默认构造函数
//    带参数构造函数
//    拷贝构造函数
//    赋值运算符overload
//    虚析构函数（可能做基类）
//    返回分量引用的下标运算符overload(从概念出发，因存在的对象行为)
//    返回向量引用的加性赋值运算符overload(从概念出发，因存在的对象行为)
//    返回向量引用的减性赋值运算符overload(从概念出发，因存在的对象行为)
//    返回向量引用的乘性赋值运算符overload(从概念出发，因存在的对象行为)
//    返回向量引用的乘性赋值(叉积)运算符overload(从概念出发，因存在的对象行为)
//    流提取运算符friend overload(从概念出发，因存在的对象行为)
//    返回分量值的下标运算符overload(从概念出发，因存在的对象行为)
//    判断向量相等运算符overload(从概念出发，因存在的对象行为)
//    判断向量不等运算符overload(从概念出发，因存在的对象行为)
//    返回向量值的加运算符overload(从概念出发，因存在的对象行为)
//    返回向量值的减运算符overload(从概念出发，因存在的对象行为)
//    返回向量值的乘运算符overload(向量*值)(从概念出发，因存在的对象行为)
//    返回向量值的乘运算符friend overload(值 * 向量)(从概念出发，因存在的对象行为)
//    返回向量值的乘(叉积)运算符overload(从概念出发，因存在的对象行为)
//    返回向量值的叉积函数(从概念出发，因存在的对象行为)
//    返回值的点积函数(从概念出发，因存在的对象行为)
//    缩放积，同点积函数(从概念出发，因存在的对象行为)
//    内积，同点积函数(从概念出发，因存在的对象行为)
//    0范数(从概念出发，因存在的对象行为)
//    1范数(从概念出发，因存在的对象行为)
//    2范数(从概念出发，因存在的对象行为)
//    P范数(从概念出发，因存在的对象行为)
//    无穷范数(从概念出发，因存在的对象行为)
//    模，同2范数函数(从概念出发，因存在的对象行为)
//    长度，同2范数函数(从概念出发，因存在的对象行为)
//    流插入运算符friend overload(从概念出发，因存在的对象行为)
//    诸分量数据成员Components(从概念出发，应存在的对象属性)
//    维度大小(维数)数据成员DIMENSION(从概念出发，应存在的类属性)
//    类派生接口：实际叉积函数，派生类根据需要重载(从概念出发，应存在的多态行为)
//    类派生接口：实际p范数函数，派生类根据需要重载(从概念出发，应存在的多态行为)
//【开发者及日期】 范静涛 2024/7/22
//【更改记录】2024/8/9 范静涛 修改维度大小(维数)常数据成员标识符为全大写DIMENSION
//------------------------------------------------------------------------------
template<class T, size_t N>
class Vector{
    //维度不可为0
    static_assert(N > 0, "Dimension must > 0");
public:
    //--------------------------------------------------------------------------
    //内嵌异常类
    //--------------------------------------------------------------------------
    //无叉积函数定义的异常
    class NO_CROSS_PRODUCT_DEFINITION : std::logic_error{
    public:
        NO_CROSS_PRODUCT_DEFINITION() : std::logic_error(
              std::string("There is no cross product function's definition in ")
            + std::to_string(N) + std::string("-dimension vector")){
        }
    };
    //无p范数定义的异常
    class NO_NORMAL_LP_DEFINITION : std::logic_error{
    public:
        NO_NORMAL_LP_DEFINITION(size_t P) : std::logic_error(
              std::string("There is no L")
            + std::to_string(P)
            + std::string("_normal function's definition in ")
            + std::to_string(N) + std::string("-dimension vector")){
        }
    };
    //--------------------------------------------------------------------------
    //必要的构造、析构、赋值行为
    //--------------------------------------------------------------------------
    //默认构造函数，默认实现
    Vector() = default;
    //带参数构造函数
    Vector(const std::array<T, N>& Source);
    //拷贝构造函数，无引用类型成员，默认实现
    Vector(const Vector& Source) = default;
    //赋值运算符overload，无引用类型成员，默认实现
    Vector& operator=(const Vector& Source) = default;
    //虚析构函数，因可为基类，声明为虚；因无成员动态构造，默认实现
    virtual ~Vector() = default;
    //--------------------------------------------------------------------------
    //非静态Setter成员函数
    //--------------------------------------------------------------------------
    //返回分量引用的下标运算符overload，从方便性角度提供
    T& operator[](size_t Index);
    //返回向量引用的加性赋值运算符overload：向量 += 向量
    Vector& operator+=(const Vector& AVector);
    //返回向量引用的减性赋值运算符overload：向量 -= 向量
    Vector& operator-=(const Vector& AVector);
    //返回向量引用的乘性赋值运算符overload：向量 *= 值
    Vector& operator*=(T AValue);
    //返回向量引用的乘性赋值(叉积)运算符overload：向量 *=(叉积) 向量
    Vector& operator*=(const Vector& AVector);
    //流提取运算符friend overload，非成员函数，无const后缀
    template<class T1, size_t N1>
    friend std::istream& operator>>(
        std::istream& Stream,
        Vector<T1, N1>& AVector);
    //--------------------------------------------------------------------------
    //非静态Getter成员函数：需检查所有Getter是否有后置const
    //--------------------------------------------------------------------------
    //返回分量值的下标运算符overload，从方便性角度提供
    T operator[](size_t Index) const;
    //向量相等运算符overload
    bool operator==(const Vector& AVector) const;
    //向量不等运算符overload
    bool operator!=(const Vector& AVector) const;
    //返回向量值的加运算符overload：向量 + 向量
    Vector operator+(const Vector& AVector) const;
    //返回向量值的减运算符overload：向量 - 向量
    Vector operator-(const Vector& AVector) const;
    //返回向量值的乘运算符overload：向量 * 值
    Vector operator*(T AValue) const;
    //返回向量值的乘运算符friend overload：值 * 向量，非成员函数，无const后缀
    template<class T1, size_t N1>
    friend Vector<T1, N1> operator*(T AValue, const Vector<T1, N1>& AVector);
    //返回向量值的乘(叉积)运算符overload：向量 *(叉积) 向量
    Vector operator*(const Vector& AVector) const;
    //返回向量值的叉积函数
    Vector CrossProduct(const Vector& AVector) const;
    //返回值的点积函数
    T DotProduct(const Vector& AVector) const;
    //缩放乘，同点积函数
    T ScalarProduct(const Vector& AVector) const;
    //内积，同点积函数
    T InnerPoduct(const Vector& AVector) const;
    //0范数
    size_t Normal_L0() const;
    //1范数
    T Normal_L1() const;
    //2范数
    T Normal_L2() const;
    //P范数
    T Normal_LP(size_t P) const;
    //无穷范数
    T Normal_LInfinity() const;
    //模，同2范数函数
    T Module() const;
    //长度，同2范数函数
    T Length() const;
    //流插入运算符friend overload，非成员函数，无const后缀
    template<class T1, size_t N1>
    friend std::ostream& operator<<(
        std::ostream& Stream,
        const Vector<T1, N1>& AVector);
    //--------------------------------------------------------------------------
    //非静态数据成员
    //--------------------------------------------------------------------------
    //分量实际存储。因无访问规则，故设为public
    StaticContainer<T, N> Components;
    //--------------------------------------------------------------------------
    //静态数据成员
    //--------------------------------------------------------------------------
    //维度大小(维数)
    static constexpr size_t DIMENSION{N};
protected:
    //--------------------------------------------------------------------------
    //受保护 非静态Getter成员函数：需检查所有Getter是否有后置const
    //--------------------------------------------------------------------------
    //实际叉积函数，派生类根据需要重载
    virtual Vector Protected_CrossProduct(const Vector& AVector) const ;
    //实际p范数函数，派生类根据需要重载
    virtual T Protected_Normal_LP(size_t P) const;
};

//------------------------------------------------------------------------------
//必要的构造、析构、赋值行为
//------------------------------------------------------------------------------

//函数名：Vector
//功能：带参数构造函数，以std::array为参构造基类部分
//入口参数：const std::array<T, N>& Source
//出口参数：无
//返回值：无
template<class T, size_t N>
Vector<T,N>::Vector(const std::array<T, N>& Source)
    :Components{StaticContainer<T, N>(Source)}{
}

//------------------------------------------------------------------------------
//非静态Setter成员函数
//------------------------------------------------------------------------------

//函数名：operator[]
//功能：返回分量引用的下标运算符overload
//入口参数：size_t Index
//出口参数：无
//返回值：指定分量的引用
template<class T, size_t N>
T& Vector<T,N>::operator[](size_t Index){
    return Components[Index];
}
//------------------------------------------------------------------------------

//函数名：operator+=
//功能：向量 += 向量，运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：向量自身的引用
template<class T, size_t N>
Vector<T,N>& Vector<T,N>::operator+=(const Vector& AVector){
    //逐一分量+=
    for (size_t i = 0; i < N; i++) {
        Components[i] += AVector.Components[i];
    }
    return *this;
}

//函数名：
//功能：向量 -= 向量，运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：向量自身的引用
template<class T, size_t N>
Vector<T,N>& Vector<T,N>::operator-=(const Vector& AVector){
    //逐一分量-=
    for (size_t i = 0; i < N; i++) {
        Components[i] -= AVector.Components[i];
    }
    return *this;
}

//函数名：operator*=
//功能：向量 *= 值
//入口参数：T AValue
//出口参数：无
//返回值：向量自身的引用，运算符overload
template<class T, size_t N>
Vector<T,N>& Vector<T,N>::operator*=(T AValue){
    //逐一分量*=值
    for (size_t i = 0; i < N; i++) {
        Components[i] *= AValue;
    }
    return *this;
}

//函数名：operator*=
//功能：向量 *=(叉积) 向量，运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：向量自身的引用
template<class T, size_t N>
Vector<T,N>& Vector<T,N>::operator*=(const Vector& AVector){
    //调用CrossProduct，赋值给自身并返回
    return operator=(CrossProduct(AVector));
}

//函数名：operator>>
//功能：流提取运算符友元实现，friend overload
//入口参数：std::istream& Stream, Vector<T, N>& AVector
//出口参数：std::istream& Stream, Vector<T, N>& AVector
//返回值：提取后的流引用
template<class T, size_t N>
std::istream& operator>>(std::istream& Stream, Vector<T, N>& AVector){
    //根据向量维度，逐一提取元素
    for (size_t i = 0; i < N; i++) {
        Stream >> AVector.Components[i];
    }
    return Stream;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//非静态Getter成员函数：需检查所有Getter是否有后置const
//------------------------------------------------------------------------------

//函数名：operator[] const
//功能：返回分量值的下标运算符overload
//入口参数：size_t Index
//出口参数：无
//返回值：指定分量的值
template<class T, size_t N>
T Vector<T,N>::operator[](size_t Index) const{
    return Components[Index];
}
//------------------------------------------------------------------------------

//函数名：operator== const
//功能：判断两向量相等的运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：所有分量相同，返回true；任一分量不同返回false
template<class T, size_t N>
bool Vector<T,N>::operator==(const Vector& AVector) const{
    return Components == AVector.Components;
}
//------------------------------------------------------------------------------

//函数名：operator!= const
//功能：判断两向量不等的运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：所有分量相同，返回false；任一分量不同返回true
template<class T, size_t N>
bool Vector<T,N>::operator!=(const Vector& AVector) const{
    return !(*this == AVector);
}
//------------------------------------------------------------------------------

//函数名：operator+ const
//功能：向量 + 向量，运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果向量
template<class T, size_t N>
Vector<T,N> Vector<T,N>::operator+(const Vector& AVector) const{
    //以自身为蓝本，构造临时向量，计算并返回
    return Vector<T, N>{*this} += AVector;
}
//------------------------------------------------------------------------------

//函数名：operator- const
//功能：向量 - 向量，运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果向量
template<class T, size_t N>
Vector<T,N> Vector<T,N>::operator-(const Vector& AVector) const{
    //以自身为蓝本，构造临时向量，计算并返回
    return Vector<T, N>{*this} -= AVector;
}
//------------------------------------------------------------------------------

//函数名：operator* const
//功能：向量 * 值，运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果向量
template<class T, size_t N>
Vector<T,N> Vector<T,N>::operator*(T AValue) const{
    //以自身为蓝本，构造临时向量，计算并返回
    return Vector<T, N>{*this} *= AValue;
}
//------------------------------------------------------------------------------

//函数名：operator* const
//功能：向量 * 值，运算符overload
//入口参数：T AValue, const Vector<T,N>& AVector
//出口参数：无
//返回值：结果向量
template<class T, size_t N>
Vector<T,N> operator*(T AValue, const Vector<T,N>& AVector){
    return AVector * AValue;
}
//------------------------------------------------------------------------------

//函数名：operator* const
//功能：向量 *(叉积) 向量，运算符overload
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果向量
template<class T, size_t N>
Vector<T,N> Vector<T,N>::operator*(const Vector& AVector) const{
    //调用CrossProduct
    return CrossProduct(AVector);
}
//------------------------------------------------------------------------------

//函数名：CrossProduct const
//功能：向量 叉积 向量
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果向量
template<class T, size_t N>
Vector<T,N> Vector<T,N>::CrossProduct(const Vector& AVector) const{
    //返回虚函数Protected_CrossProduct的调用结果
    return Protected_CrossProduct(AVector);
}
//------------------------------------------------------------------------------

//函数名：DotProduct const
//功能：向量 点积 向量
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果值
template<class T, size_t N>
T Vector<T,N>::DotProduct(const Vector& AVector) const{
    //T类型必须可以初始化为0
    T Sum = 0;
    //逐一元素*，累加
    for (size_t i = 0; i < N; i++) {
        Sum += Components[i] * AVector.Components[i];
    }
    return Sum;
}
//------------------------------------------------------------------------------

//函数名：ScalarProduct const
//功能：缩放积，同：向量 点积 向量
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果值
template<class T, size_t N>
T Vector<T,N>::ScalarProduct(const Vector& AVector) const{
    return DotProduct(AVector);
}
//------------------------------------------------------------------------------

//函数名：InnerPoduct const
//功能：内积，同：向量 点积 向量
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果值
template<class T, size_t N>
T Vector<T,N>::InnerPoduct(const Vector& AVector) const{
    return DotProduct(AVector);
}
//------------------------------------------------------------------------------

//函数名：Normal_L0 const
//功能：0范数
//入口参数：无
//出口参数：无
//返回值：不为0分量的个数
template<class T, size_t N>
size_t Vector<T,N>::Normal_L0() const{
    //不为零分量个数累加器，初始化为0
    size_t NonZeroCount = 0;
    //逐一累加不为0的分量个数
    for (size_t i = 0; i < N; i++) {
        NonZeroCount += Components[i] != 0;
    }
    return NonZeroCount;
}
//------------------------------------------------------------------------------

//函数名：Normal_L1 const
//功能：1范数
//入口参数：无
//出口参数：无
//返回值：所有分量的绝对值之和
template<class T, size_t N>
T Vector<T,N>::Normal_L1() const{
    //T类型必须可初始化为0
    T Sum = 0;
    for (size_t i = 0; i < N; i++) {
        //T类型必可默认转换为可求值类型，如double等
        Sum += std::abs(Components[i]);
    }
    return Sum;
}
//------------------------------------------------------------------------------

//函数名：Normal_L2 const
//功能：2范数
//入口参数：无
//出口参数：无
//返回值：所有分量平方和的算数平方根
template<class T, size_t N>
T Vector<T,N>::Normal_L2() const{
    //T类型必须可初始化为0
    T Sum = 0;
    //逐一分量平方，累加
    for (size_t i = 0; i < N; i++) {
        //T类型必须有*运算符
        Sum += Components[i] * Components[i];
    }
    //T类型必须可隐性转换为可求值类型，并可用可求值类型构造
    return static_cast<T>(std::sqrt(Sum));
}
//------------------------------------------------------------------------------

//函数名：Normal_LP const
//功能：p范数
//入口参数：无
//出口参数：无
//返回值：T类型结果值
template<class T, size_t N>
T Vector<T,N>::Normal_LP(size_t P) const{
    switch(P){
        //调用并返回0范数计算结果
        case 0 : return Normal_L0();
        //调用并返回1范数计算结果
        case 1 : return Normal_L1();
        //调用并返回2范数计算结果
        case 2 : return Normal_L2();
        //调用并返回Protected_Normal_LP函数计算结果
        default: return Protected_Normal_LP(P);
    }
}
//------------------------------------------------------------------------------

//函数名：Normal_LInfinity
//功能：无穷范数
//入口参数：无
//出口参数：无
//返回值：最大分量值
template<class T, size_t N>
T Vector<T,N>::Normal_LInfinity() const{
    T Max = Components[0];
    for (size_t i = 1; i < N; i++) {
        //T类型必须与>运算符
        Max = Components[i] > Max ? Components : Max;
    }
    return Max;
}
//------------------------------------------------------------------------------

//函数名：Module const
//功能：求模，同2范数
//入口参数：无
//出口参数：无
//返回值：所有分量平方和的算数平方根
template<class T, size_t N>
T Vector<T,N>::Module() const{
    return Normal_L2();
}
//------------------------------------------------------------------------------

//函数名：Length const
//功能：求长度，同2范数
//入口参数：无
//出口参数：无
//返回值：所有分量平方和的算数平方根
template<class T, size_t N>
T Vector<T,N>::Length() const{
    return Normal_L2();
}
//------------------------------------------------------------------------------

//函数名：operator<<
//功能：流插入运算符友元实现，friend overload
//入口参数：std::ostream& Stream, const Vector<T, N>& AVector
//出口参数：std::ostream& Stream
//返回值：插入后的流引用
template<class T, size_t N>
std::ostream& operator<<(std::ostream& Stream, const Vector<T, N>& AVector){
    //逐分量插入，后接空格
    for (size_t i = 0; i < N - 1; i++) {
        Stream << AVector.Components[i] << ' ';
    }
    //最后分量后无空格
    Stream << AVector.Components[N - 1];
    return Stream;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//受保护的，非静态Getter成员函数：需检查所有Getter是否有后置const
//------------------------------------------------------------------------------

//函数名：Protected_CrossProduct const
//功能：派生类叉积接口，默认实现为抛出异常
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果向量
template<class T, size_t N>
Vector<T,N> Vector<T,N>::Protected_CrossProduct(const Vector& AVector) const{
    throw NO_CROSS_PRODUCT_DEFINITION();
}
//------------------------------------------------------------------------------

//函数名：Protected_Normal_LP const
//功能：派生类p范数接口，默认实现为抛出异常
//入口参数：const Vector& AVector
//出口参数：无
//返回值：结果值
template<class T, size_t N>
T Vector<T,N>::Protected_Normal_LP(size_t P) const{
    throw NO_NORMAL_LP_DEFINITION(P);
}
//------------------------------------------------------------------------------

#endif /* Vector_h */
